#!/bin/bash
#
# Copyright (C) 2015 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
# Copyright (C) 2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
#
# SPDX-License-Identifier: LGPL-2.1-only

TEST_DESC="UST - Blocking mode"

CURDIR=$(dirname $0)/
TESTDIR=$CURDIR/../../..
SESSION_NAME="blocking"
CHANNEL_NAME="testchan"

TESTAPP_PATH="$TESTDIR/utils/testapp"
TESTAPP_NAME="gen-ust-events"
TESTAPP_BIN="$TESTAPP_PATH/$TESTAPP_NAME/$TESTAPP_NAME"
EVENT_NAME="tp:tptest"

NUM_TESTS=49

# shellcheck source=../utils/utils.sh
source "$TESTDIR/utils/utils.sh"

# MUST set TESTDIR before calling those functions
# Run app on a single CPU to ensure we only write in a single ring buffer.
function run_app()
{
	taskset --cpu-list "$(get_any_available_cpu)" $TESTAPP_BIN -i $NUM_EVENT
	ok $? "Application done"
}

function check_disk_space()
{
	local path

	path="${1:?}"
	kb_free=$(df -k -P "${path}" | tail -n 1 | awk '{ print $4 }')
	if [ "${kb_free}" -lt "1048576" ] ; then
		return 1
	fi

	return 0
}

function test_ust_implicit_no_blocking()
{
	NUM_EVENT=5000000
	diag "UST implicit non-blocking mode (default): will hang if fails"

	start_lttng_sessiond
	# session in no-output mode
	create_lttng_session_no_output $SESSION_NAME
	enable_ust_lttng_event_ok $SESSION_NAME "$EVENT_NAME"
	start_lttng_tracing_ok $SESSION_NAME
	run_app
	stop_lttng_tracing_ok $SESSION_NAME
	destroy_lttng_session_ok $SESSION_NAME
	stop_lttng_sessiond

	ok 0 "Does not hang"
}

function test_ust_implicit_no_blocking_with_channel_blocking()
{
	NUM_EVENT=5000000
	diag "UST implicit non-blocking mode (default) with blocking-timeout=inf channel: will hang if fails"

	start_lttng_sessiond
	# session in no-output mode
	create_lttng_session_no_output $SESSION_NAME
	enable_ust_lttng_channel_ok $SESSION_NAME $CHANNEL_NAME "--blocking-timeout=inf"
	enable_ust_lttng_event_ok $SESSION_NAME "$EVENT_NAME" $CHANNEL_NAME
	start_lttng_tracing_ok $SESSION_NAME
	run_app
	stop_lttng_tracing_ok $SESSION_NAME
	destroy_lttng_session_ok $SESSION_NAME
	stop_lttng_sessiond

	ok 0 "Does not hang"
}

function test_ust_timeout_no_blocking()
{
	NUM_EVENT=12500
	diag "UST 1ms timeout blocking mode: will hang if fails"

	start_lttng_sessiond
	# session in no-output mode
	create_lttng_session_no_output $SESSION_NAME
	# blocking timeout 1ms
	enable_ust_lttng_channel_ok $SESSION_NAME $CHANNEL_NAME "--blocking-timeout=1000"
	enable_ust_lttng_event_ok $SESSION_NAME "$EVENT_NAME" $CHANNEL_NAME
	start_lttng_tracing_ok $SESSION_NAME
	LTTNG_UST_ALLOW_BLOCKING=1 run_app
	stop_lttng_tracing_ok $SESSION_NAME
	destroy_lttng_session_ok $SESSION_NAME
	stop_lttng_sessiond

	ok 0 "Does not hang"
}

function test_ust_snapshot_no_blocking()
{
	NUM_EVENT=5000000
	diag "UST blocking mode: don't block in snapshot mode"

	# Test without the plugin
	start_lttng_sessiond
	create_lttng_session_ok $SESSION_NAME $TRACE_PATH --snapshot
	# blocking timeout 1ms
	enable_ust_lttng_channel_ok $SESSION_NAME $CHANNEL_NAME "--blocking-timeout=1000"
	enable_ust_lttng_event_ok $SESSION_NAME "$EVENT_NAME" $CHANNEL_NAME
	start_lttng_tracing_ok $SESSION_NAME
	LTTNG_UST_ALLOW_BLOCKING=1 run_app
	stop_lttng_tracing_ok $SESSION_NAME
	destroy_lttng_session_ok $SESSION_NAME
	stop_lttng_sessiond

	ok 0 "Does not hang"
}

function test_ust_blocking_no_discard()
{
	NUM_EVENT=5000000
	diag "UST blocking mode: no event discarded"

	# Test without the plugin
	start_lttng_sessiond
	create_lttng_session_ok $SESSION_NAME $TRACE_PATH
	# infinite blocking timeout
	enable_ust_lttng_channel_ok $SESSION_NAME $CHANNEL_NAME "--blocking-timeout=inf"
	enable_ust_lttng_event_ok $SESSION_NAME "$EVENT_NAME" $CHANNEL_NAME
	start_lttng_tracing_ok $SESSION_NAME
	LTTNG_UST_ALLOW_BLOCKING=1 run_app
	stop_lttng_tracing_ok $SESSION_NAME
	discarded=$("${XML_EXTRACT}" <("${TESTDIR}/../src/bin/lttng/${LTTNG_BIN}" --mi=xml list --channel="${CHANNEL_NAME}" "${SESSION_NAME}") '//lttng:command/lttng:output/lttng:sessions/lttng:session/lttng:domains/lttng:domain/lttng:channels/lttng:channel/lttng:attributes/lttng:discarded_events')
	destroy_lttng_session_ok $SESSION_NAME
	stop_lttng_sessiond

	test "$(echo "${discarded}" | grep -Eo '[0-9]+')" = "0"
	ok $? "No event lost with UST blocking mode: ${discarded}"
}

plan_tests $NUM_TESTS

print_test_banner "$TEST_DESC"

bail_out_if_no_babeltrace

if ! check_disk_space "${TMPDIR:-/tmp}"; then
	BAIL_OUT "Not enough free space to run blocking tests"
fi

TESTS=(
	"test_ust_implicit_no_blocking"
	"test_ust_implicit_no_blocking_with_channel_blocking"
	"test_ust_timeout_no_blocking"
	"test_ust_snapshot_no_blocking"
	"test_ust_blocking_no_discard"
)

TEST_COUNT=${#TESTS[@]}
i=0

while [ "$i" -lt "$TEST_COUNT" ]; do

	TRACE_PATH=$(mktemp -d -t tmp.test_blocking_ust_trace_path.XXXXXX)

	# Execute test
	${TESTS[$i]}

	rm -rf $TRACE_PATH

	let "i++"
done
